home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 408_01 / history.c < prev    next >
Text File  |  1993-08-06  |  9KB  |  369 lines

  1. /*
  2.     SNEWS 1.91
  3.  
  4.     History routines
  5.  
  6.  
  7.     Copyright (C) 1991  John McCombs, Christchurch, NEW ZEALAND
  8.                         john@ahuriri.gen.nz
  9.                         PO Box 2708, Christchurch, NEW ZEALAND
  10.  
  11.     Modifications copyright (C) 1993  Daniel Fandrich
  12.                         <dan@fch.wimsey.bc.ca> or CompuServe 72365,306
  13.  
  14.     This program is free software; you can redistribute it and/or modify
  15.     it under the terms of the GNU General Public License, version 1, as
  16.     published by the Free Software Foundation.
  17.  
  18.     This program is distributed in the hope that it will be useful,
  19.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.     GNU General Public License for more details.
  22.  
  23.     See the file COPYING, which contains a copy of the GNU General
  24.     Public License.
  25.  
  26.  
  27.     Source is formatted with a tab size of 4.
  28.  */
  29.  
  30.  
  31. #include "defs.h"
  32. #include "history.h"
  33. #include <alloc.h>
  34.  
  35.  
  36. FILE *hist;
  37. HIST_LIST *hlist;
  38.  
  39.  
  40. /*----------------------- open hist file for writing ------------------------*/
  41. FILE *open_hist_file(void)
  42. {
  43.     /*
  44.      *  This routine opens the history file for writing, positioned after
  45.      *  the last record.
  46.      */
  47.  
  48.     char fn[256];
  49.  
  50.     sprintf(fn, "%shistory", my_stuff.news_dir);
  51.  
  52.     if ((hist = fopen(fn, "ab")) == NULL) {
  53.         fprintf(stderr, "history: cannot open file %s for append\n", fn);
  54.         exit(1);
  55.     }
  56.  
  57.     return(hist);
  58. }
  59.  
  60.  
  61.  
  62. /*---------------------------- close hist file ---------------------------*/
  63. void close_hist_file(void)
  64. {
  65.     /*
  66.      *  This routine closes the history file
  67.      */
  68.  
  69.     fclose(hist);
  70. }
  71.  
  72.  
  73. /*---------------------------- add record -------------------------------*/
  74. void add_hist_record(char *msg_id, char *ng)
  75. {
  76.     /*
  77.      *  This routine adds a record to the history files.  It is passed the
  78.      *  message id, and the newsgroup list.  The newsgroup list is unwound,
  79.      *  and the article numbers are added to the record.
  80.      *
  81.      *  If there is only one valid newsgroup no history record is written
  82.      *
  83.      *  We assume that this routine is called after the article has been
  84.      *  posted, so that the article counters are correct.
  85.      */
  86.  
  87.  
  88.     char   *p, buf[512];
  89.     ACTIVE *a;
  90.     time_t t;
  91.     int    ct;
  92.  
  93.     time(&t);
  94.  
  95.     /* count the newsgroups */
  96.     ct = 0;
  97.     strcpy(buf, ng);
  98.     p = strtok(buf, " \t,\n\r");
  99.  
  100.     while (p != NULL) {
  101.         if (stricmp(find_news_group(p)->group, "junk") != 0)
  102.             ct++;
  103.         p = strtok(NULL, " \t,\n\r");
  104.     }
  105.  
  106.  
  107.     if (ct > 1) {                /* more than one active newsgroup */
  108.  
  109.         strcpy(buf, ng);
  110.         p = strtok(buf, " \t,\n\r");
  111.  
  112.         if ((p != NULL) && (strlen(msg_id) > 0)) {
  113.  
  114.             fprintf(hist, "%s %09ld ", msg_id, t);
  115.  
  116.             while (p != NULL) {
  117.                 a = find_news_group(p);
  118.                 if (stricmp(a->group, "junk") != 0)
  119.                     fprintf(hist, "%s %08ld  ", a->group, a->hi_num);
  120.                 p = strtok(NULL, " \t,\n\r");
  121.             }
  122.             fprintf(hist, "\n");
  123.         }
  124.     }
  125. }
  126.  
  127.  
  128.  
  129.  
  130.  
  131. /*--------------------- read history file into ram -------------------------*/
  132. HIST_LIST *load_history_list(void)
  133. {
  134.     /*
  135.      *  This routine opens and reads the history file, building and index
  136.      *
  137.      *  Load this after active and ng files.  Set HIST_MEM_LIMIT in defs.h
  138.      *  to ensure there is enough memory left
  139.      */
  140.  
  141.     char      buf[512];
  142.     long      where;
  143.     HIST_LIST *h;
  144.  
  145.     sprintf(buf, "%shistory", my_stuff.news_dir);
  146.  
  147.     /* open the file */
  148.     if ((hist = fopen(buf, "rb")) == NULL) {
  149.         fprintf(stderr, "history: cannot open file %s for reading\n", buf);
  150.         exit(1);
  151.     }
  152.  
  153.     where = 0;
  154.     hlist = h = NULL;
  155.  
  156.     while (fgets(buf, 511, hist)) {
  157.  
  158.         if (hlist == NULL) {
  159.             hlist = xmalloc(sizeof(HIST_LIST));
  160.             h = hlist;
  161.         } else {
  162.             h->next = xmalloc(sizeof(HIST_LIST));
  163.             h = h->next;
  164.         }
  165.  
  166.         h->mid = hash_msg_id(strtok(buf, " \t\n\r"));
  167.         h->offset = where;
  168.  
  169.         #if !defined(__OS2__)     /* no need for the following under OS/2 */
  170.         /* leave some memory for other things */
  171.         if (farcoreleft() < HIST_MEM_LIMIT)
  172.             break;
  173.         #endif
  174.  
  175.         where = ftell(hist);
  176.     } /* while */
  177.  
  178.     if (h)
  179.         h->next = NULL;
  180.  
  181.     return(hlist);
  182. }
  183.  
  184.  
  185.  
  186.  
  187. /*------------------------- release the history list ----------------------*/
  188. void free_hist_list(void)
  189. {
  190.     /*
  191.      *  Close the history file and free the memory list
  192.      */
  193.     HIST_LIST *h;
  194.  
  195.     close_hist_file();
  196.  
  197.     while (hlist != NULL) {
  198.         h = hlist->next;
  199.         free(hlist);
  200.         hlist = h;
  201.     }
  202. }
  203.  
  204.  
  205.  
  206.  
  207. /*-------------------------- find history entry -----------------------------*/
  208. HIST_LIST *find_msg_id(char *msg_id)
  209. {
  210.     /*
  211.      *  Look up the history list and return the entry for the req'd msg id
  212.      *  or NULL if not found.
  213.      */
  214.  
  215.     HIST_LIST *h = hlist;
  216.     long      hashed_id = hash_msg_id(msg_id);
  217.  
  218.     while (h) {
  219.         if (h->mid == hashed_id)
  220.             break;
  221.         h = h->next;
  222.     }
  223.     return(h);
  224. }
  225.  
  226.  
  227.  
  228.  
  229. /*----------------------- lookup cross posts --------------------------------*/
  230. CROSS_POSTS *look_up_history(char *msg_id, char *ng)
  231. {
  232.     /*
  233.      *  This routine returns a linked list of the groups to which
  234.      *  an article has been crossposted.  Self is excluded.  To do
  235.      *  this we:
  236.      *      - hash the msg id
  237.      *      - search the list of id's
  238.      *      - if a hit is found we read it from the hist file
  239.      *      - decode the record, excluding self
  240.      *      - build a CROSS_POSTS list
  241.      *
  242.      *  NULL is returned if there were no crossposts.  ASSUMES global
  243.      *  file 'hist' is open.  If it isn't this routine always returns
  244.      *  NULL
  245.      */
  246.  
  247.     long        hid;
  248.     HIST_LIST   *h;
  249.     CROSS_POSTS *cx, *c;
  250.     char        buf[512], *p;
  251.  
  252.     hid = hash_msg_id(msg_id);
  253.  
  254.     /* look for the crosspost entry */
  255.     h = hlist;
  256.     while (h != NULL) {
  257.         if (h->mid == hid) break;
  258.         h = h->next;
  259.     }
  260.  
  261.     /* now look up the history file */
  262.     cx = NULL;
  263.     if (h && (h->mid == hid)) {
  264.         fseek(hist, h->offset, SEEK_SET);
  265.         if (fgets(buf, 511, hist) != NULL) {
  266.  
  267.             /*
  268.              *  Compare the target msg id with the one on the file.  If they
  269.              *  are different then the must be a hash collision - just abort
  270.              */
  271.             p = strtok(buf, " \t\n\r");
  272.             if (stricmp(p, msg_id) == 0) {
  273.  
  274.  
  275.                 /* skip the date field and leave pointing to the first group */
  276.                 strtok(NULL, " \t\n\r");
  277.                 p = strtok(NULL, " \t\n\r");
  278.  
  279.                 while (p != NULL) {
  280.  
  281.                     /* exclude self */
  282.                     if (stricmp(p, ng) != 0) {
  283.                         if (cx == NULL) {
  284.                             cx = xmalloc(sizeof(CROSS_POSTS));
  285.                             c = cx;
  286.                         } else {
  287.                             c->next = xmalloc(sizeof(CROSS_POSTS));
  288.                             c = c->next;
  289.                         }
  290.  
  291.                         strcpy(c->group, p);
  292.                         p = strtok(NULL, " \t\n\r");
  293.                         c->art_num = atol(p);
  294.                         c->next = NULL;
  295.  
  296.                     } else {
  297.                         /* eat article number */
  298.                         p = strtok(NULL, " \t\n\r");
  299.                     }
  300.  
  301.                     p = strtok(NULL, " \t\n\r");
  302.                 }
  303.  
  304.             }
  305.         }
  306.     }
  307.  
  308.     return(cx);
  309.  
  310. }
  311.  
  312.  
  313.  
  314. /*----------------------- deallocate crosspost list --------------------------*/
  315. void free_cross_post_list(CROSS_POSTS *cx)
  316. {
  317.     CROSS_POSTS *c;
  318.  
  319.     while (cx != NULL) {
  320.         c = cx->next;
  321.         free(cx);
  322.         cx = c;
  323.     }
  324.  
  325. }
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332. /*--------------------- pseudo-random number generator ----------------------*/
  333. long seed;
  334.  
  335. long xrand(void)
  336. {
  337.     return (seed = (seed * 16807) & 0x7FFFFFFFL);
  338. }
  339.  
  340.  
  341.  
  342. /*-----------